﻿using LoungeRepo.Contracts.Core;
using LoungeRepo.Contracts.EntityStore;
using LoungeRepo.Contracts.Normalizer;
using LoungeRepo.Contracts.Serialization;
using LoungeRepo.EntityStore;
using LoungeRepo.Normalizer;
using LoungeRepo.Serialization;

namespace LoungeRepo.Core
{
    public partial class LoungeRepository : ILoungeRepository
    {
        public const string DEFAULT_LOUNGE_REPOSITORY_ROOT_FOLDER_NAME = "LoungeRepository.Root";
        public const string DEFAULT_PARTITION_NAME = "~Default";

        private readonly IEntityNormalizer normalizer;
        private readonly INormalizedEntitySerializer serializer;
        private readonly IEntityStore filesys;


        public LoungeRepository() : this(DEFAULT_LOUNGE_REPOSITORY_ROOT_FOLDER_NAME) {}
        public LoungeRepository(string rootFolderPath)
        {
            this.normalizer = new EntityNormalizer(OnResolveEntityReferenceRequest);
            this.serializer = new BinarySerializer();
            this.filesys = new FilesystemEntityStore(rootFolderPath);
        }


        public void Store(object nonEntityRoot, string id) { Store(nonEntityRoot, id, DEFAULT_PARTITION_NAME); }
        public void Store(object nonEntityRoot, string id, string parition)
        {
            var normalizedEntities = this.normalizer.Normalize(nonEntityRoot, id, parition);
            PersistNormalizedEntities(normalizedEntities);
        }

        public void Store(object entityRoot)
        {
            var normalizedEntities = this.normalizer.Normalize(entityRoot);
            PersistNormalizedEntities(normalizedEntities);
        }


        public T Load<T>(string id) { return Load<T>(id, DEFAULT_PARTITION_NAME); }
        public T Load<T>(string id, string partition)
        {
            INormalizedEntity normalizedEntity = DepersistNormalizedEntity(id, partition);
            return (T)this.normalizer.Denormalize(normalizedEntity);
        }


        public void Delete(string id) { Delete(id, DEFAULT_PARTITION_NAME);  }
        public void Delete(string id, string partition)
        {
            this.filesys.Delete(id, partition);
        }


        private INormalizedEntity OnResolveEntityReferenceRequest(ILoungeRepoEntityIdentity entityReference)
        {
            return DepersistNormalizedEntity(entityReference.Id, entityReference.Partition);
        }


        #region Implementation of IDisposable
        public void Dispose()
        {}
        #endregion
    }
}
